﻿using BUGCOME.Infrastructure;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using NetTaste;
using Swashbuckle.AspNetCore.Filters;
using Swashbuckle.AspNetCore.SwaggerUI;
using System.Diagnostics;

namespace BUGCOME.Signalr.Api.Extensions
{
    /// <summary>
    /// Swagger 配置扩展类
    /// 提供 Swagger 文档生成和 UI 配置的扩展方法
    /// </summary>
    public static class SwaggerExtension
    {
        /// <summary>
        /// 添加 Swagger 配置
        /// 配置 Swagger 文档生成选项，包括分组、安全定义和文档包含规则
        /// </summary>
        /// <param name="services">服务集合</param>
        public static void AddSwaggerConfig(this IServiceCollection services)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }
            services.AddSwaggerGen(c =>
            {
                // 定义名为 "signalr" 的文档组，用于展示路由相关 API
                c.SwaggerDoc("signalr", new OpenApiInfo
                {
                    Title = "BUGCOME.Signalr.Api",
                    Version = "v1",
                    Description = "即时通信"
                });

                try
                {
                    // 添加项目各层的 XML 注释文件，用于生成更详细的 API 文档
                    var baseDir = AppContext.BaseDirectory;
                    c.IncludeXmlComments(Path.Combine(baseDir, "BUGCOME.Model.xml"), true);
                    c.IncludeXmlComments(Path.Combine(baseDir, "BUGCOME.ServiceCore.xml"), true);
                    c.IncludeXmlComments(Path.Combine(baseDir, "BUGCOME.Service.xml"), true);
                    c.IncludeXmlComments(Path.Combine(baseDir, "BUGCOME.Signalr.Api.xml"), true);

                    //// 添加当前程序集的 XML 注释
                    //var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                    //var xmlPath = Path.Combine(baseDir, xmlFile);
                    //c.IncludeXmlComments(xmlPath);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("swagger 文档加载失败" + ex.Message);
                }

                // 添加响应头过滤器，用于处理响应头信息
                c.OperationFilter<AddResponseHeadersFilter>();

                // 添加授权摘要过滤器，在 API 摘要中显示授权信息
                c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();

                // 添加安全需求过滤器，处理 API 的安全需求
                c.OperationFilter<SecurityRequirementsOperationFilter>();

                // 定义 JWT 认证安全方案
                var securitySchemeName = JwtBearerDefaults.AuthenticationScheme;
                c.AddSecurityDefinition(securitySchemeName,
                    new OpenApiSecurityScheme
                    {
                        In = ParameterLocation.Header,  // Token 放置在请求头中
                        Description = "请输入Login接口返回的Token，前置Bearer。示例：Bearer {Token}",
                        Name = "Authorization",         // 请求头中的字段名
                        Type = SecuritySchemeType.ApiKey, // 认证类型为 API Key
                        BearerFormat = "JWT",           // Token 格式为 JWT
                        Scheme = securitySchemeName     // 安全方案名称
                    });

                // 应用安全方案到所有 API
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = securitySchemeName }
                        },
                        new List<string>()
                    }
                });

                // 配置文档包含规则，决定哪些 API 应该包含在哪个文档组中
                c.DocInclusionPredicate((docName, apiDescription) =>
                {
                    // 获取 API 的组名（通过 ApiExplorerSettings 特性指定）
                    var groupName = apiDescription.GroupName;

                    // 如果 API 没有指定组名，则包含在所有文档中
                    if (string.IsNullOrEmpty(groupName))
                        return true;

                    // 只将 API 包含在与组名匹配的文档中
                    // 例如：标记为 [ApiExplorerSettings(GroupName = "auth")] 的 API 只包含在 "auth" 文档中
                    return groupName == docName;
                });
            });
        }

        /// <summary>
        /// 使用 Swagger 中间件
        /// 配置 Swagger JSON 生成和 Swagger UI 显示
        /// </summary>
        /// <param name="app">应用构建器</param>
        public static void UseSwagger(this IApplicationBuilder app)
        {
            app.UseSwagger(c =>
            {
                // 配置 Swagger JSON 路由模板
                c.RouteTemplate = "swagger/{documentName}/swagger.json";

                // 添加预序列化过滤器，用于动态设置 Swagger 文档的服务器 URL
                c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
                {
                    // 默认使用当前请求的协议和主机作为服务器 URL
                    var url = $"{httpReq.Scheme}://{httpReq.Host.Value}";

                    // 如果请求头中包含开发环境代理信息，则使用该代理作为服务器 URL
                    var referer = httpReq.Headers["Referer"].ToString();
                    if (referer.Contains(GlobalConstant.DevApiProxy))
                        url = referer[..(referer.IndexOf(GlobalConstant.DevApiProxy, StringComparison.InvariantCulture) + GlobalConstant.DevApiProxy.Length - 1)];

                    // 设置 Swagger 文档的服务器 URL
                    swaggerDoc.Servers =
                        new List<OpenApiServer>
                        {
                            new OpenApiServer
                            {
                                Url = url
                            }
                        };
                });
            });

            // 配置 Swagger UI
            app.UseSwaggerUI(c =>
            {
                // 添加名为 "auth" 的文档组的端点
                c.SwaggerEndpoint("/swagger/signalr/swagger.json", "即时通信");


                // 设置 API 文档默认折叠，不自动展开
                c.DocExpansion(DocExpansion.None);
            });
        }
    }
}
